package com.ymx.darling.executor.statement;

import com.ymx.darling.bean.sql.BoundSql;
import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.session.setting.Callable;

import java.sql.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * 存储过程的语句处理器
 * @author 爱Java的小于
 */
public class CallableStatementHandler extends PreparedStatementHandler{
    public CallableStatementHandler(Statement statement) {
        super(statement);
    }

    @Override
    public PreparedStatement preparedStatement (Connection connection, BoundSql boundSql)throws SQLException {
        return connection.prepareCall(boundSql.getSql());
    }


    /**
     * 注册输出参数
     * @param cs {@code CallableStatement}
     * @throws SQLException 可能会抛出此异常
     */
    private void registerOutputParameters(CallableStatement cs) throws SQLException {
        Callable callable = this.getStatement().getCallable();
        callable.registerOutputParameters(cs);
    }


    /**
     * 处理out参数
     * @param cs CallableStatement
     */
    private void handleOutputParameters(CallableStatement cs)throws SQLException {
        Callable callable = this.getStatement().getCallable();
        callable.handleOutputParameters(cs);
    }


    @Override
    public void setParameters(PreparedStatement preparedStatement, List<Object> paramList)throws SQLException {
        super.setParameters(preparedStatement, paramList);
        this.registerOutputParameters((CallableStatement) preparedStatement);
    }


    @Override
    public int update(PreparedStatement preparedStatement)throws SQLException{
        CallableStatement cs = (CallableStatement) preparedStatement;
        cs.execute();
        this.handleOutputParameters(cs);
        return cs.getUpdateCount();
    }


    @Override
    public <T> List<T> queryList(PreparedStatement preparedStatement)throws SQLException {
        CallableStatement cs = (CallableStatement) preparedStatement;
        boolean execute = cs.execute();
        this.handleOutputParameters(cs);
        if (execute) {
            List<List<T>> resultLists = new LinkedList<>();
            do {
                ResultSet resultSet = cs.getResultSet();
                List<T> result = this.handResultSet(resultSet);
                resultLists.add(result);
            } while (cs.getMoreResults());
            // 判断返回结果集个数
            return resultLists.size() == 1 ? resultLists.get(0) : (List<T>) resultLists;
        } else {
            return Collections.emptyList();
        }
    }
}
